#include <base/TcpServer.hpp>

TcpServer* TcpServer::instance_ = nullptr;
std::mutex TcpServer::mutex_;

TcpServer* TcpServer::GetInstance(int port) 
{
    if (instance_ == nullptr)  {
        TcpServer::mutex_.lock();
        if (TcpServer::instance_ == nullptr) {
            TcpServer::instance_ = new TcpServer(port);
            TcpServer::instance_ -> InitTcpServer();
        }
        TcpServer::mutex_.unlock();
    } 
    return TcpServer::instance_;
}

TcpServer::TcpServer(int port)
    :listen_sock_(-1), port_(port)
{ 
    
}

TcpServer::~TcpServer()
{
    delete TcpServer::instance_;
    CHECK_CLOSE_RESET_FD(listen_sock_);
}

void TcpServer::InitTcpServer()
{
    Sock();
    Bind();
    Listen();
}

void TcpServer::Sock()
{
    listen_sock_ = socket(AF_INET, SOCK_STREAM, 0);
    if (listen_sock_ < 0) {
        LogFatal("Failed to create socket");
        exit(1);
    }
    LogInfo("listen_sock_: %d", listen_sock_);

    int opt = 1;
    setsockopt(listen_sock_, SOL_SOCKET, SO_REUSEADDR, (void*)&opt, sizeof(opt));
    LogInfo("setsockopt SO_REUSEADDR");
}

void TcpServer::Bind()
{
    sockaddr_in local_addr;
    memset(&local_addr, 0, sizeof(local_addr));
    local_addr.sin_family = AF_INET;
    local_addr.sin_port = htons(port_);
    local_addr.sin_addr.s_addr = INADDR_ANY;
    socklen_t len = sizeof(local_addr);

    if (bind(listen_sock_, (const sockaddr *)&local_addr, len) < 0) {
        LogFatal("Failed to bind socket");
        exit(1);
    }
    LogInfo("bind success");
}

void TcpServer::Listen()
{
    int res = listen(listen_sock_, BACKLOG);
    if (res == -1) {
        LogFatal("Failed to listen socket");
        exit(1);
    }
    LogInfo("listen success");
}

int TcpServer::GetListenSock()
{
    return listen_sock_;
}
